/*
 * 4输入+1输出的就绪队列，对应输入的push_en信号拉高后，将对应的内容存储，最多支持同时写4个字
 * ready信号拉高后，可以读取到正确的队列输出value
*/

module ok_queue (
    input wire clk,
    input wire rst,
    input wire push_en_1,            //输入端口1的使能信号
    input wire [4:0] push_value_1,   //输入端口1的内容信号，使能位拉高则存储到队列，拉低则不响应
    input wire push_en_2,            //输入端口2的使能信号
    input wire [4:0] push_value_2,   //输入端口2的内容信号，使能位拉高则存储到队列，拉低则不响应
    input wire push_en_3,            //输入端口3的使能信号
    input wire [4:0] push_value_3,   //输入端口3的内容信号，使能位拉高则存储到队列，拉低则不响应
    input wire push_en_4,            //输入端口4的使能信号
    input wire [4:0] push_value_4,   //输入端口4的内容信号，使能位拉高则存储到队列，拉低则不响应
    output reg pop_ready,            //输出端口1的就绪信号
    output reg [4:0] pop_value       //输出端口1的内容信号，就绪信号拉高后，此信号有效
);

    reg [4:0] queue [0:15];
    reg [4:0] queue_head, queue_tail;

    initial begin
        queue_head <= 0;
        queue_tail <= 0;
    end

    //每个时钟上升沿检查push使能信号，将数组加入到队列中
    always @(posedge clk) begin
        if (rst) begin
            //处理复位信号
            queue_head <= 0;
            queue_tail <= 0;
            pop_ready <= 0;
        end
        else begin
            if (push_en_1 && push_en_2 && push_en_3 && push_en_4) begin
                queue[queue_tail] <= push_value_1;
                queue[(queue_tail+1)%16] <= push_value_2;
                queue[(queue_tail+2)%16] <= push_value_3;
                queue[(queue_tail+3)%16] <= push_value_4;
                queue_tail <= (queue_tail+4)%16;
            end
            if (push_en_1 && push_en_2 && push_en_3 && !push_en_4) begin
                queue[queue_tail] <= push_value_1;
                queue[(queue_tail+1)%16] <= push_value_2;
                queue[(queue_tail+2)%16] <= push_value_3;
                queue_tail <= (queue_tail+3)%16;
            end
            if (push_en_1 && push_en_2 && push_en_4 && !push_en_3) begin
                queue[queue_tail] <= push_value_1;
                queue[(queue_tail+1)%16] <= push_value_2;
                queue[(queue_tail+2)%16] <= push_value_4;
                queue_tail <= (queue_tail+3)%16;
            end
            if (push_en_4 && push_en_2 && push_en_3 && !push_en_1) begin
                queue[queue_tail] <= push_value_2;
                queue[(queue_tail+1)%16] <= push_value_3;
                queue[(queue_tail+2)%16] <= push_value_4;
                queue_tail <= (queue_tail+3)%16;
            end
            if (push_en_1 && push_en_4 && push_en_3 && !push_en_2) begin
                queue[queue_tail] <= push_value_1;
                queue[(queue_tail+1)%16] <= push_value_4;
                queue[(queue_tail+2)%16] <= push_value_3;
                queue_tail <= (queue_tail+3)%16;
            end
            if (push_en_1 && push_en_2 && !push_en_3 && !push_en_4) begin
                queue[queue_tail] <= push_value_1;
                queue[(queue_tail+1)%16] <= push_value_2;
                queue_tail <= (queue_tail+2)%16;
            end
            if (push_en_1 && push_en_3 && !push_en_2 && !push_en_4) begin
                queue[queue_tail] <= push_value_1;
                queue[(queue_tail+1)%16] <= push_value_3;
                queue_tail <= (queue_tail+2)%16;
            end
            if (push_en_1 && push_en_4 && !push_en_3 && !push_en_2) begin
                queue[queue_tail] <= push_value_1;
                queue[(queue_tail+1)%16] <= push_value_4;
                queue_tail <= (queue_tail+2)%16;
            end
            if (push_en_2 && push_en_3 && !push_en_1 && !push_en_4) begin
                queue[queue_tail] <= push_value_3;
                queue[(queue_tail+1)%16] <= push_value_2;
                queue_tail <= (queue_tail+2)%16;
            end
            if (push_en_2 && push_en_4 && !push_en_3 && !push_en_1) begin
                queue[queue_tail] <= push_value_4;
                queue[(queue_tail+1)%16] <= push_value_2;
                queue_tail <= (queue_tail+2)%16;
            end
            if (push_en_3 && push_en_4 && !push_en_1 && !push_en_2) begin
                queue[queue_tail] <= push_value_3;
                queue[(queue_tail+1)%16] <= push_value_4;
                queue_tail <= (queue_tail+2)%16;
            end
            if (push_en_1 && !push_en_2 && !push_en_3 && !push_en_4) begin
                queue[queue_tail] <= push_value_1;
                queue_tail <= (queue_tail+1)%16;
            end
            if (push_en_2 && !push_en_1 && !push_en_3 && !push_en_4) begin
                queue[queue_tail] <= push_value_2;
                queue_tail <= (queue_tail+1)%16;
            end
            if (push_en_3 && !push_en_2 && !push_en_1 && !push_en_4) begin
                queue[queue_tail] <= push_value_3;
                queue_tail <= (queue_tail+1)%16;
            end
            if (push_en_4 && !push_en_2 && !push_en_3 && !push_en_1) begin
                queue[queue_tail] <= push_value_4;
                queue_tail <= (queue_tail+1)%16;
            end
        end
    end

    //每个时钟对外发射一组内容
    always @(posedge clk) begin
        if (queue_head != queue_tail) begin
            pop_value <= queue[queue_head];
            queue_head <= (queue_head+1)%16;
            pop_ready <= 1;
        end
        else begin
            pop_ready <= 0;
        end
    end
endmodule